package com.kaibes.module.token.filter;

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.kaibes.module.token.core.TokenEncryptions;
import com.kaibes.module.token.core.TokenUtils;
import com.kaibes.module.token.pojo.Token;
import com.kaibes.module.token.service.TokenService;
import com.kaibes.web.encryption.EncryptionRes;
import com.kaibes.web.filter.BeforeFilterInternal;
import com.kaibes.web.util.UserAgentUtils;

@Order(11)
@Component
public class TokenBeforeFilter implements BeforeFilterInternal {

    @Autowired
    private TokenService tokenService;
    @Autowired
    private TokenEncryptions tokenEncryptions;
    
    private Logger logger = LoggerFactory.getLogger(TokenBeforeFilter.class);
    
    @Override
    public boolean beforeFilterInternal(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取TOKEN=====================================================
        String tokenStr = null;
        
        // 从COOKIE里找
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("token")) {
                    tokenStr = cookie.getValue();
                    break;
                }
            }
        }
        
        // 从头信息里找
        if (tokenStr == null) {
            tokenStr = request.getHeader("token");
        }
        if (tokenStr == null) {
            tokenStr = request.getHeader("authorization");
            if (tokenStr != null && tokenStr.startsWith("Bearer ")) {
                tokenStr = tokenStr.substring(7);
            }
        }
        
        // 从URL里找
        if (tokenStr == null) {
            tokenStr = request.getParameter("token");
        }
        
        if (tokenStr == null) {
            TokenUtils.deleteSecretTokenFromCookie(request, response);
            return false;
        }
        
        Token token = null;
        try {
            token = tokenEncryptions.readToken(tokenStr);
            if (TokenUtils.isExpired(token)) {
                logger.info("token is expired !");
                TokenUtils.deleteAllFromCookie(request, response);
                return false;
            }
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException
                | InvalidAlgorithmParameterException | IllegalBlockSizeException | IllegalArgumentException | BadPaddingException e) {
            logger.error(request.getRequestURI()+" token read failure !");
//            e.printStackTrace();
            TokenUtils.deleteAllFromCookie(request, response);
            return false;
        }
        
        if (!UserAgentUtils.getUserAgentStr(request).startsWith(token.getType().getValue())) {
            logger.info("token type is incorrected !");
            TokenUtils.deleteAllFromCookie(request, response);
            return false;
        }
        
        Token temp = tokenService.getByUserIdAndType(token.getUserId(), token.getType());
        if (temp == null) {
            logger.info("token does not exits !");
            TokenUtils.deleteAllFromCookie(request, response);
            return false;
        } else {
            request.setAttribute(EncryptionRes.AES_KEY, token.getAesKey());
            request.setAttribute(EncryptionRes.AES_IV, token.getAesIv());
            request.setAttribute("token", token);
            return false;
        }
        
    }

}
